﻿//using System;
using System.Xml;
using SharpDX.Direct3D11;
using SharpDX;
using System.Runtime.InteropServices;
using SharpDX.Direct3D;

namespace Engine
{
    public class EESkyBox : System.IDisposable
    {
        TextureContainer[] RVtextures;
        TextureContainer RVStarsDisp;
        TextureContainer RVGrad;
        TextureContainer RVDiff;
        TextureContainer RVRand;
        MeshContainer MContains;
        EffectContainer EEEM;

        Texture2D CubeTexture;
        RenderTargetView[] CubeRenderTarget;
        public ShaderResourceView CubeSRV;
        const int MipLevel = 8;
        const int Size = 1024;

        SamplerState SSWrapMipLinear;

        SkyShaderConstants SSC;
        Buffer SkyConstantsBuffer;

        int CMaxParticl = 20000;

        int MaxParticl = 0;

        float time = 0f;
        float TP = 0f;
        float Cikl = 90000f;//mili


        #region IDisposable
        ~EESkyBox()
        {
            Dispose();
        }
        public void Dispose()
        {
            if (MContains != null) MContains.Dispose();
            if (SkyConstantsBuffer != null) SkyConstantsBuffer.Dispose();
            if (SSWrapMipLinear != null) SSWrapMipLinear.Dispose();
            if (CubeSRV != null) CubeSRV.Dispose();
            for (int i = 0; i < 6; i++)
            {
                if (CubeRenderTarget != null && CubeRenderTarget[i] != null) CubeRenderTarget[i].Dispose();
            }
            if (CubeTexture != null) CubeTexture.Dispose();
        }
        #endregion

        public EESkyBox()
        {

        }
        
        public float GetStarsDisp(byte[] T_Dist, int s_x, int s_y, Vector3 Vec3)
        {
            double Teta = System.Math.Acos(Vec3.Y / System.Math.Sqrt(Vec3.X * Vec3.X + Vec3.Y * Vec3.Y + Vec3.Z * Vec3.Z)) / System.Math.PI;
            double Psi = System.Math.Atan(Vec3.Z / (Vec3.X)) / (2f * System.Math.PI);
	        if (Vec3.X<0) Psi+=0.5f;
	        if (Vec3.X>=0 && Vec3.Z<0) Psi+=1f;
            Psi += 0.25f;
            if (Psi > 1) Psi -= 1f;
            int x = (int)(Psi * (double)s_x);
            int y = (int)(Teta * (double)s_y);
            return (float)T_Dist[4 * (x + y * s_x)] / 255f;
        }

        public float GetStarsSize(byte[] T_Dist, int s_x, int s_y, Vector3 Vec3)
        {
            double Teta = System.Math.Acos(Vec3.Y / System.Math.Sqrt(Vec3.X * Vec3.X + Vec3.Y * Vec3.Y + Vec3.Z * Vec3.Z)) / System.Math.PI;
            double Psi = System.Math.Atan(Vec3.Z / (Vec3.X)) / (2f * System.Math.PI);
            if (Vec3.X < 0) Psi += 0.5f;
            if (Vec3.X >= 0 && Vec3.Z < 0) Psi += 1f;

            Psi += 0.25f;
            if (Psi > 1) Psi -= 1f;

            int x = (int)(Psi * (double)s_x);
            int y = (int)(Teta * (double)s_y);
            return (float)T_Dist[1+4 * (x + y * s_x)] / 255f;
        }

        public void InitStars(int Seed, int CMaxParticl, int s_factor1, int s_factor2, float s_size)
        {
            int s_x = RVStarsDisp.Texture2d.Description.Width;
            int s_y = RVStarsDisp.Texture2d.Description.Height;
            
            byte[] T_Dist = new byte[(s_x * s_y * 4)];
            using (DataStream dataStream = new DataStream(T_Dist.Length, true, true)) {
                //dataStream.Write(T_Dist, 0, T_Dist.Length);
                Texture2D.ToStream<Texture2D>(ModelViewer.Program.context, RVStarsDisp.Texture2d, ImageFileFormat.Dds, dataStream);
            }
            Seed = T_Dist[0];
            System.Random Random_ = new System.Random(Seed);
            float Sc = 1050f / Global.Settings.Height;
            MaxParticl = (int)((float)CMaxParticl * (1f/Sc));




            //Texture2DDescription T2DD = new Texture2DDescription{}
            /////////////////////////////////////////////////////////////////////////////////////////
            /*
            GraphicsDevice device = Global.Game.GraphicsDevice;
            VertexDeclaration = ParticleVertex.VertexDeclaration;
            vertexBuffer = new DynamicVertexBuffer[6];
            vertexBuffer[0] = new DynamicVertexBuffer(device, VertexDeclaration, MaxParticl * 4, BufferUsage.WriteOnly);
            vertexBuffer[1] = new DynamicVertexBuffer(device, VertexDeclaration, MaxParticl * 4, BufferUsage.WriteOnly);
            vertexBuffer[2] = new DynamicVertexBuffer(device, VertexDeclaration, MaxParticl * 4, BufferUsage.WriteOnly);
            vertexBuffer[3] = new DynamicVertexBuffer(device, VertexDeclaration, MaxParticl * 4, BufferUsage.WriteOnly);
            vertexBuffer[4] = new DynamicVertexBuffer(device, VertexDeclaration, MaxParticl * 4, BufferUsage.WriteOnly);
            vertexBuffer[5] = new DynamicVertexBuffer(device, VertexDeclaration, MaxParticl * 4, BufferUsage.WriteOnly);

            ////////////////////
            for (int IndVB = 0; IndVB < 6; IndVB++)
            {
                particles = new ParticleVertex[MaxParticl * 4];
                int i = 0;
                while (i < MaxParticl)
                {
                    Vector3 V = GetNormalDispersion(Random_);
                    float Size = GetStarsSize(T_Dist, s_x, s_y, V);
                    Size *= s_size;
                    float Disp = 1f;
                    if (GetStarsDisp(T_Dist, s_x, s_y, V) < (float)Random_.NextDouble())
                    {
                        V = GetNormalDispersion(Random_);
                        if (GetStarsDisp(T_Dist, s_x, s_y, V) < (float)Random_.NextDouble())
                        {
                            V = GetNormalDispersion(Random_);
                            if (GetStarsDisp(T_Dist, s_x, s_y, V) < (float)Random_.NextDouble()) Disp = 0f;
                        }
                    }
                    if (TestVector(V) == IndVB)
                    {
                        particles[i * 4 + 0].Corner = new Short2(-1, -1);
                        particles[i * 4 + 1].Corner = new Short2(1, -1);
                        particles[i * 4 + 2].Corner = new Short2(1, 1);
                        particles[i * 4 + 3].Corner = new Short2(-1, 1);

                        particles[i * 4 + 0].Position = V * 100f;
                        particles[i * 4 + 0].Velocity = new Vector3();
                        particles[i * 4 + 0].color = new Color(
                            (float)Random_.NextDouble(),
                            (float)Random_.NextDouble(),
                            (float)Random_.NextDouble(),
                            (float)Random_.NextDouble());
                        
                        particles[i * 4 + 0].Time = (float)Random_.NextDouble() * 10f;
                        float siz = (float)Random_.NextDouble();
                        particles[i * 4 + 0].Parametr = new Vector4(
                        Disp * 0.4f * Sc * (1.4f + (float)Math.Pow(siz, 20f) * 3.0f * ((float)Random_.NextDouble() / 2f + 0.5f) + (float)Math.Pow(siz, s_factor1) * 3.0f * Size + (float)Math.Pow(siz, s_factor2) * 1.0f * Size)
                            , siz, 0, 0);
                        for (int ii = 1; ii < 4; ii++)
                        {
                            particles[i * 4 + ii].Position = particles[i * 4 + 0].Position;
                            particles[i * 4 + ii].Velocity = particles[i * 4 + 0].Velocity;
                            particles[i * 4 + ii].color = particles[i * 4 + 0].color;
                            particles[i * 4 + ii].Time = particles[i * 4 + 0].Time;
                            particles[i * 4 + ii].Parametr = particles[i * 4 + 0].Parametr;
                            particles[i * 4 + ii].Parametr2 = particles[i * 4 + 0].Parametr2;
                        }

                        i++;
                    }
                }
                int stride = ParticleVertex.SizeInBytes;
                vertexBuffer[IndVB].SetData(0, particles, 0, MaxParticl * 4, stride);
            }

            ushort[] indices_ = new ushort[MaxParticl * 6];
            for (int i = 0; i < MaxParticl; i++)
            {
                indices_[i * 6 + 0] = (ushort)(i * 4 + 0);
                indices_[i * 6 + 1] = (ushort)(i * 4 + 1);
                indices_[i * 6 + 2] = (ushort)(i * 4 + 2);
                indices_[i * 6 + 3] = (ushort)(i * 4 + 0);
                indices_[i * 6 + 4] = (ushort)(i * 4 + 2);
                indices_[i * 6 + 5] = (ushort)(i * 4 + 3);
            }

            indexBuffer = new IndexBuffer(device, typeof(ushort), indices_.Length, BufferUsage.WriteOnly);
            indexBuffer.SetData(indices_);


            PEffect = Global.Game.Content.Load<Effect>("shaders/effects/Stars_eff");
            effectProjectionParameter = PEffect.Parameters["Projection"];
            effectViewportScaleParameter = PEffect.Parameters["ViewportScale"];
            effectTimeParameter = PEffect.Parameters["CurrentTime"];

            Diff = Global.Game.Content.Load<Texture2D>("textures/effects/particle02");
            Rand = Global.Game.Content.Load<Texture2D>("textures/effects/Random2Kx4");
            Grad = Global.Game.Content.Load<Texture2D>("textures/effects/gradient");
            */
        }

        public void Initialize()
        {
            LoadSky(0);

            Texture2DDescription descTex = new Texture2DDescription();
            descTex.ArraySize = 6;
            descTex.Width = Size;
            descTex.Height = Size;
            descTex.Usage = ResourceUsage.Default;
            descTex.CpuAccessFlags = CpuAccessFlags.None;
            descTex.Format = SharpDX.DXGI.Format.R8G8B8A8_UNorm;
            descTex.SampleDescription = new SharpDX.DXGI.SampleDescription(1, 0);
            descTex.MipLevels = MipLevel;
            descTex.BindFlags = BindFlags.ShaderResource | BindFlags.RenderTarget;
            descTex.OptionFlags = ResourceOptionFlags.GenerateMipMaps | ResourceOptionFlags.TextureCube;

            //Create the texture and shader view
            CubeTexture = new Texture2D(ModelViewer.Program.device, descTex);
            CubeSRV = new ShaderResourceView(ModelViewer.Program.device, CubeTexture);

            RenderTargetViewDescription RTVD = new RenderTargetViewDescription();
            RTVD.Format = descTex.Format;
            RTVD.Dimension = RenderTargetViewDimension.Texture2DArray;
            RTVD.Texture2DArray.FirstArraySlice = 0;
            RTVD.Texture2DArray.ArraySize = 1;
            RTVD.Texture2DArray.MipSlice = 0;
            
            CubeRenderTarget = new RenderTargetView[6];


            for (int i = 0; i < 6; i++)
            {
                RTVD.Texture2DArray.FirstArraySlice = i;
                CubeRenderTarget[i] = new RenderTargetView(ModelViewer.Program.device, CubeTexture, RTVD);
            }

            SamplerStateDescription a = new SamplerStateDescription();
            a.AddressU = TextureAddressMode.Clamp;
            a.AddressV = TextureAddressMode.Clamp;
            a.AddressW = TextureAddressMode.Clamp;
            a.Filter = Filter.MinMagMipLinear;
            SSWrapMipLinear = new SamplerState(ModelViewer.Program.device, a);

            MContains = new MeshContainer();
            MContains.BytesPerVertex = 20;
            MContains.FaceCount = 12;
            MContains.VertexsCount = 24;

            Vector3 vExtents = new Vector3(500, 500, 500);

            var vertices = new DataStream(MContains.BytesPerVertex * MContains.VertexsCount, true, true);

            //Back
            vertices.Write(new Vector3(-vExtents.X, -vExtents.Y, vExtents.Z));
            vertices.Write(new Vector2(1, 1));
            vertices.Write(new Vector3(-vExtents.X, vExtents.Y, vExtents.Z));
            vertices.Write(new Vector2(1, 0));
            vertices.Write(new Vector3(vExtents.X, vExtents.Y, vExtents.Z));
            vertices.Write(new Vector2(0, 0));
            vertices.Write(new Vector3(vExtents.X, -vExtents.Y, vExtents.Z));
            vertices.Write(new Vector2(0, 1));
            //Front
            vertices.Write(new Vector3(vExtents.X, -vExtents.Y, -vExtents.Z));
            vertices.Write(new Vector2(1, 1));
            vertices.Write(new Vector3(vExtents.X, vExtents.Y, -vExtents.Z));
            vertices.Write(new Vector2(1, 0));
            vertices.Write(new Vector3(-vExtents.X, vExtents.Y, -vExtents.Z));
            vertices.Write(new Vector2(0, 0));
            vertices.Write(new Vector3(-vExtents.X, -vExtents.Y, -vExtents.Z));
            vertices.Write(new Vector2(0, 1));
            //Bottom
            vertices.Write(new Vector3(-vExtents.X, -vExtents.Y, -vExtents.Z));
            vertices.Write(new Vector2(0, 0));
            vertices.Write(new Vector3(-vExtents.X, -vExtents.Y, vExtents.Z));
            vertices.Write(new Vector2(0, 1));
            vertices.Write(new Vector3(vExtents.X, -vExtents.Y, vExtents.Z));
            vertices.Write(new Vector2(1, 1));
            vertices.Write(new Vector3(vExtents.X, -vExtents.Y, -vExtents.Z));
            vertices.Write(new Vector2(1, 0));
            //Top
            vertices.Write(new Vector3(vExtents.X, vExtents.Y, -vExtents.Z));
            vertices.Write(new Vector2(1, 1));
            vertices.Write(new Vector3(vExtents.X, vExtents.Y, vExtents.Z));
            vertices.Write(new Vector2(1, 0));
            vertices.Write(new Vector3(-vExtents.X, vExtents.Y, vExtents.Z));
            vertices.Write(new Vector2(0, 0));
            vertices.Write(new Vector3(-vExtents.X, vExtents.Y, -vExtents.Z));
            vertices.Write(new Vector2(0, 1));
            //Left
            vertices.Write(new Vector3(-vExtents.X, vExtents.Y, -vExtents.Z));
            vertices.Write(new Vector2(1, 0));
            vertices.Write(new Vector3(-vExtents.X, vExtents.Y, vExtents.Z));
            vertices.Write(new Vector2(0, 0));
            vertices.Write(new Vector3(-vExtents.X, -vExtents.Y, vExtents.Z));
            vertices.Write(new Vector2(0, 1));
            vertices.Write(new Vector3(-vExtents.X, -vExtents.Y, -vExtents.Z));
            vertices.Write(new Vector2(1, 1));
            //Right
            vertices.Write(new Vector3(vExtents.X, -vExtents.Y, -vExtents.Z));
            vertices.Write(new Vector2(0, 1));
            vertices.Write(new Vector3(vExtents.X, -vExtents.Y, vExtents.Z));
            vertices.Write(new Vector2(1, 1));
            vertices.Write(new Vector3(vExtents.X, vExtents.Y, vExtents.Z));
            vertices.Write(new Vector2(1, 0));
            vertices.Write(new Vector3(vExtents.X, vExtents.Y, -vExtents.Z));
            vertices.Write(new Vector2(0, 0));



            vertices.Position = 0;
            InputElement[] elements11 = new[] {
                new InputElement("POSITION", 0, SharpDX.DXGI.Format.R32G32B32_Float, 0, 0) ,
                new InputElement("TEXCOORD", 0, SharpDX.DXGI.Format.R32G32_Float, 12, 0)};

            MContains.Vertexs = new Buffer(ModelViewer.Program.device, vertices, MContains.BytesPerVertex * MContains.VertexsCount, ResourceUsage.Default, BindFlags.VertexBuffer, CpuAccessFlags.None, ResourceOptionFlags.None, 0);

            var indices = new DataStream(4 * MContains.FaceCount * 3, true, true);
            for (int x = 0; x < 6; x++)
            {
                indices.Write((int)(x * 4 + 0));
                indices.Write((int)(x * 4 + 1));
                indices.Write((int)(x * 4 + 2));

                indices.Write((int)(x * 4 + 2));
                indices.Write((int)(x * 4 + 3));
                indices.Write((int)(x * 4 + 0));
            }
            indices.Position = 0;

            MContains.Indices = new Buffer(ModelViewer.Program.device, indices, 4 * MContains.FaceCount * 3, ResourceUsage.Default, BindFlags.IndexBuffer, CpuAccessFlags.None, ResourceOptionFlags.None, 0);
            MContains.binding = new VertexBufferBinding(MContains.Vertexs, MContains.BytesPerVertex, 0);

            EEEM = ContentManager.LoadEffect("Content/Shaders/SkyBox", elements11);


            // Подготовка константного буффера
            BufferDescription bd = new BufferDescription();
            bd.SizeInBytes = Marshal.SizeOf(typeof(SkyShaderConstants));
            bd.Usage = ResourceUsage.Dynamic;
            bd.BindFlags = BindFlags.ConstantBuffer;
            bd.CpuAccessFlags = CpuAccessFlags.Write;
            bd.OptionFlags = ResourceOptionFlags.None;
            bd.StructureByteStride = 0;

            SkyConstantsBuffer = new Buffer(ModelViewer.Program.device, bd);
            SSC = new SkyShaderConstants();

        }
        
        public void Draw(float TimeMili, Device device, DeviceContext context, EEDCamera Camera)
        {
            time += TimeMili;
            if (time > Cikl) time = 0;
            TP = time / Cikl;
            if (EEEM == null || RVtextures == null) return;

            Matrix viewMatrix = Matrix.LookAtRH(new Vector3(), Camera.direction, Camera.up_vector);
            Matrix worldMatrix = Matrix.Translation(new Vector3());
            Vector3 vCameraDirection = Camera.direction;

            SSC.WVP = Matrix.Transpose(worldMatrix * viewMatrix * Camera.projectionMatrix);

            //Загружаем геометрию
            context.InputAssembler.InputLayout = EEEM.layout;
            context.InputAssembler.PrimitiveTopology = PrimitiveTopology.TriangleList;
            context.InputAssembler.SetVertexBuffers(0, MContains.binding);
            context.InputAssembler.SetIndexBuffer(MContains.Indices, SharpDX.DXGI.Format.R32_UInt, 0);
            //Получаем буффер из структуры, структурируем и помещаем в GPU

            var dataBox = ModelViewer.Program.context.MapSubresource(SkyConstantsBuffer, 0, MapMode.WriteDiscard, SharpDX.Direct3D11.MapFlags.None);
            Utilities.Write(dataBox.DataPointer, ref SSC);
            ModelViewer.Program.context.UnmapSubresource(SkyConstantsBuffer, 0);


            //Устанавливаем эффект
            //int Technique = 0; int Pass = 0;
            EEEM.renderTechniques[0].GetPassByIndex(0).Apply(ModelViewer.Program.context);
            //Константный буффер передается шейдерам
            ModelViewer.Program.device.ImmediateContext.VertexShader.SetConstantBuffer(0, SkyConstantsBuffer);
            ModelViewer.Program.device.ImmediateContext.PixelShader.SetConstantBuffer(0, SkyConstantsBuffer);
            ModelViewer.Program.context.PixelShader.SetSampler(0,SSWrapMipLinear);


            for (int x = 0; x < 6; x++)
            {
                float f = 0;
                switch (x)
                {
                    case 0: //зад
                        f = Vector3.Dot(vCameraDirection, new Vector3(0f, 0f, -1f));
                        break;
                    case 1: //перед
                        f = Vector3.Dot(vCameraDirection, new Vector3(0f, 0f, 1f));
                        break;
                    case 2: //низ
                        f = Vector3.Dot(vCameraDirection, new Vector3(0f, 1f, 0f));
                        break;
                    case 3: //верх
                        f = Vector3.Dot(vCameraDirection, new Vector3(0f, -1f, 0f));
                        break;
                    case 4: //лево
                        f = Vector3.Dot(vCameraDirection, new Vector3(1f, 0f, 0f));
                        break;
                    case 5: //право
                        f = Vector3.Dot(vCameraDirection, new Vector3(-1f, 0f, 0f));
                        break;
                }

                if (f - 0.5f <= 0)
                {
                    ModelViewer.Program.context.PixelShader.SetShaderResource(0, RVtextures[x].TextureResource);
                    //Program.context.PixelShader.SetSampler(SSWrapMipLinear, 0);
                    ModelViewer.Program.context.DrawIndexed(6, x * 6, 0);
                }

            }
            /*
            GraphicsDevice device = Global.Game.GraphicsDevice;
            for (int x = 0; x < 6; x++)
            {
            //...
                if (f - 0.5f <= 0)
                {
                    

                    effectProjectionParameter.SetValue(cam_.projectionMatrix);
                    effectViewportScaleParameter.SetValue(new Vector2(0.5f / device.Viewport.AspectRatio, -0.5f));
                    effectTimeParameter.SetValue(0f);
                    PEffect.Parameters["baseTexture"].SetValue(Diff);
                    PEffect.Parameters["RTexture"].SetValue(Rand);
                    PEffect.Parameters["GTexture"].SetValue(Grad);
                    //PEffect.Parameters["DTexture"].SetValue(Depth);
                    PEffect.Parameters["H"].SetValue(Global.Game.GraphicsDevice.Viewport.Height);
                    PEffect.Parameters["W"].SetValue(Global.Game.GraphicsDevice.Viewport.Width);
                    PEffect.Parameters["VP"].SetValue(worldMatrix * viewMatrix * projectionMatrix);
                    PEffect.Parameters["CurrentTime"].SetValue(TP);
                    PEffect.Parameters["cubeTexture"].SetValue(RTCube);
                    PEffect.CurrentTechnique = PEffect.Techniques["Particles"];
                    PEffect.CurrentTechnique.Passes[0].Apply();


                    device.SetVertexBuffer(vertexBuffer[x]);
                    device.Indices = indexBuffer;
                    device.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, MaxParticl * 4, 0, MaxParticl * 2);
                }
            }*/

        }
        
        private static int TestVector(Vector3 Vect)
        {
            if (Vect.Length() == 0) return -1;
            Vect.Normalize();
            Vect *= 5f;

            if (PerOtr(new Vector2(), new Vector2(Vect.X, Vect.Z), new Vector2(-1f, -1f), new Vector2(1f, -1f)) && PerOtr(new Vector2(), new Vector2(Vect.Y, Vect.Z), new Vector2(-1f, -1f), new Vector2(1f, -1f)))
                return 0;
            if (PerOtr(new Vector2(), new Vector2(Vect.X, Vect.Z), new Vector2(-1f, 1f), new Vector2(1f, 1f)) && PerOtr(new Vector2(), new Vector2(Vect.Y, Vect.Z), new Vector2(-1f, 1f), new Vector2(1f, 1f)))
                return 1;
            if (PerOtr(new Vector2(), new Vector2(Vect.X, Vect.Y), new Vector2(-1f, -1f), new Vector2(1f, -1f)) && PerOtr(new Vector2(), new Vector2(Vect.Z, Vect.Y), new Vector2(-1f, -1f), new Vector2(1f, -1f)))
                return 2;
            if (PerOtr(new Vector2(), new Vector2(Vect.X, Vect.Y), new Vector2(-1f, 1f), new Vector2(1f, 1f)) && PerOtr(new Vector2(), new Vector2(Vect.Z, Vect.Y), new Vector2(-1f, 1f), new Vector2(1f, 1f)))
                return 3;
            if (PerOtr(new Vector2(), new Vector2(Vect.Z, Vect.X), new Vector2(-1f, 1f), new Vector2(1f, 1f)) && PerOtr(new Vector2(), new Vector2(Vect.Y, Vect.X), new Vector2(-1f, 1f), new Vector2(1f, 1f)))
                return 4;
            if (PerOtr(new Vector2(), new Vector2(Vect.Z, Vect.X), new Vector2(-1f, -1f), new Vector2(1f, -1f)) && PerOtr(new Vector2(), new Vector2(Vect.Y, Vect.X), new Vector2(-1f, -1f), new Vector2(1f, -1f)))
                return 5;
            //0 зад
            //1 перед
            //2 низ
            //3 верх
            //4 лево
            //5 право
            return 0;
        }
        
        private static bool PerOtr(Vector2 Seg1_N, Vector2 Seg1_K, Vector2 Seg2_N, Vector2 Seg2_K)
        {
            float x1 = Seg1_N.X;
            float y1 = Seg1_N.Y;
            float x2 = Seg1_K.X;
            float y2 = Seg1_K.Y;
            float x3 = Seg2_N.X;
            float y3 = Seg2_N.Y;
            float x4 = Seg2_K.X;
            float y4 = Seg2_K.Y;

            return (((x3 - x1) * (y2 - y1) - (y3 - y1) * (x2 - x1)) * ((x4 - x1) * (y2 - y1) - (y4 - y1) * (x2 - x1)) <= 0)
                && (((x1 - x3) * (y4 - y3) - (y1 - y3) * (x4 - x3)) * ((x2 - x3) * (y4 - y3) - (y2 - y3) * (x4 - x3)) <= 0);
        }
        
        public void RenderCubemap()
        {
            ViewportF[] V = ModelViewer.Program.context.Rasterizer.GetViewports();

            Viewport CubeV = new Viewport(0, 0, Size, Size);
            ModelViewer.Program.context.Rasterizer.SetViewports(CubeV);

            Render(CubeRenderTarget[0], RVtextures[5].TextureResource, true);//L
            Render(CubeRenderTarget[1], RVtextures[4].TextureResource, true);//R
            Render(CubeRenderTarget[2], RVtextures[3].TextureResource, false);//Top
            Render(CubeRenderTarget[3], RVtextures[2].TextureResource, false);//Bottom
            Render(CubeRenderTarget[4], RVtextures[0].TextureResource, true);//Back
            Render(CubeRenderTarget[5], RVtextures[1].TextureResource, true);//F

            ModelViewer.Program.context.GenerateMips(CubeSRV);
            ModelViewer.Program.context.Rasterizer.SetViewports(V);
        }
        

        public void Render(RenderTargetView RTV, ShaderResourceView InResurce, bool Invert)
        {
            ModelViewer.Program.context.OutputMerger.SetTargets(RTV);

            ModelViewer.Program.context.ClearRenderTargetView(RTV, new Color4(0.0f, 1.0f, 0.0f, 1.0f));

            QuadScreen.Render(ModelViewer.Program.device, ModelViewer.Program.context, InResurce, SSWrapMipLinear, Invert);


            /*
            Global.Game.GraphicsDevice.SetRenderTarget(RTC, CMF);//>>>>>>>>>>>>>>>>>>>>>
            Global.Game.spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.Opaque, SamplerState.PointClamp, DepthStencilState.Default, RasterizerState.CullNone);
            Global.Game.spriteBatch.Draw(Tex, new Rectangle(0, 0, RTCube.Size, RTCube.Size), new Rectangle(0, 0, Tex.Width, Tex.Height), Color.White);//<<<<<<<<<<<<<<<<<<<<<
            Global.Game.spriteBatch.End();
            Global.Game.GraphicsDevice.SetRenderTarget(null);*/
        }
        
        public Vector3 GetNormalDispersion(System.Random Random_)
        {
            //Преобразование Бокса — Мюллера
            double x = Random_.NextDouble() * 2d - 1d;
            double y = Random_.NextDouble() * 2d - 1d;
            double z = Random_.NextDouble() * 2d - 1d;
            double s = x * x + y * y + z * z;
            while (s <= 0 || s > 1)
            {
                x = Random_.NextDouble() * 2d - 1d;
                y = Random_.NextDouble() * 2d - 1d;
                z = Random_.NextDouble() * 2d - 1d;

                s = x * x + y * y + z * z;
            }
            double t = System.Math.Sqrt((-3 * System.Math.Log(s)) / s);
            double z0 = x * t;
            double z1 = y * t;
            double z2 = z * t;
            Vector3 r = new Vector3((float)z0, (float)z1, (float)z2);
            r.Normalize();
            return r;
        }
        
        /// <summary>
        /// Загрузить указанный скайбокс
        /// </summary>
        /// <param name="Index">Индекс в файле скайбоксов</param>
        public void LoadSky(uint Index)
        {
            RVtextures = new TextureContainer[6];

            float  s_size = 1.0f;
            int s_count = 10000, s_factor1 = 25, s_factor2 = 50;
            ModelViewer.Program.MyScene.InitCubeMap = true;
            try
            {
                XmlTextReader reader = new XmlTextReader("GameData/SkyList.xml");
                while (reader.Read())
                {
                    if (reader.Name == "sky" && Index == System.Convert.ToInt32(reader.GetAttribute("id")))
                    {
                        reader.Read();
                        reader.Read();
                        if (reader.Name == "back")
                        {
                            RVtextures[0] = ContentManager.LoadTexture2D(reader.GetAttribute("path"));
                        }
                        reader.Read();
                        reader.Read();
                        if (reader.Name == "fron")
                        {
                            RVtextures[1] = ContentManager.LoadTexture2D(reader.GetAttribute("path"));
                        }
                        reader.Read();
                        reader.Read();
                        if (reader.Name == "bttm")
                        {
                            RVtextures[2] = ContentManager.LoadTexture2D(reader.GetAttribute("path"));
                        }
                        reader.Read();
                        reader.Read();
                        if (reader.Name == "topp")
                        {
                            RVtextures[3] = ContentManager.LoadTexture2D(reader.GetAttribute("path"));
                        }
                        reader.Read();
                        reader.Read();
                        if (reader.Name == "left")
                        {
                            RVtextures[4] = ContentManager.LoadTexture2D(reader.GetAttribute("path"));
                        }
                        reader.Read();
                        reader.Read();
                        if (reader.Name == "rght")
                        {
                            RVtextures[5] = ContentManager.LoadTexture2D(reader.GetAttribute("path"));
                        }
                        reader.Read();
                        reader.Read();
                        if (reader.Name == "star_disp")
                        {
                            RVStarsDisp = ContentManager.LoadTexture2D(reader.GetAttribute("path"));
                        }
                        reader.Read();
                        reader.Read();
                        if (reader.Name == "star_grad")
                        {
                            RVGrad = ContentManager.LoadTexture2D(reader.GetAttribute("path"));
                        }
                        reader.Read();
                        reader.Read();
                        if (reader.Name == "star_count")
                        {
                            s_count = System.Convert.ToInt32(reader.GetAttribute("int"));
                        }
                        reader.Read();
                        reader.Read();
                        if (reader.Name == "star_factor1")
                        {
                            s_factor1 = System.Convert.ToInt32(reader.GetAttribute("int"));
                        }
                        reader.Read();
                        reader.Read();
                        if (reader.Name == "star_factor2")
                        {
                            s_factor2 = System.Convert.ToInt32(reader.GetAttribute("int"));
                        }
                        reader.Read();
                        reader.Read();
                        if (reader.Name == "star_size")
                        {
                            s_size = System.Convert.ToInt32(reader.GetAttribute("int"));
                            InitStars((int)Index, s_count, s_factor1, s_factor2, s_size/100f);
                            /////////////////
                            return;
                        }
                    }
                }
            }

            catch
            {
                System.Windows.Forms.MessageBox.Show("Error! Проблема при чтении 'GameData/SkyList.xml' O_O. Запаролся на индесе " + Index.ToString());
                //throw new XmlException("Error! Проблема при чтении 'GameData/ModelList.xml' O_O. Запаролся на индесе " + p_ind.ToString());
            }
            System.Windows.Forms.MessageBox.Show("Error! Проблема при чтении 'GameData/SkyList.xml' O_O. Нет такого скайбокса, либо скайбокс прописан с ошибкой: " + Index.ToString());
            //throw new XmlException("Error! Проблема при чтении 'GameData/ModelList.xml' O_O. Запаролся на индесе " + p_ind.ToString());
            for (int i = 0; i < 6; i++)
            {
                RVtextures[i] = ContentManager.LoadTexture2D("Content/Textures/Def_light");
            }
            RVStarsDisp = ContentManager.LoadTexture2D("Content/Textures/Def_occl");
            RVGrad = ContentManager.LoadTexture2D("Content/Textures/Def_occl");

            InitStars((int)Index, s_count, s_factor1, s_factor2, s_size);
        }

        private struct SkyShaderConstants
        {
            public Matrix WVP;
        }
    }
}